package com.sig.util;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;

import java.sql.Timestamp;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAdjusters;
import java.util.List;

/**
 * 日期时间处理工具(jdk8)
 *
 * @author sig
 * @since 2019/3/14
 */
public final class DateTimeUtil {
    /** 当天重置时间戳 */
    private static long dayResetTime;
    /** 明天重置时间戳 */
    private static long tomorrowResetTime;
    /** 昨天重置时间戳 */
    private static long yesterdayResetTime;

    private DateTimeUtil() {
    }

    private static void resetTime() {
        final long zeroMilli = zeroMilli();
        dayResetTime = zeroMilli;
        tomorrowResetTime = zeroMilli + DateUtils.MILLIS_PER_DAY;
        yesterdayResetTime = zeroMilli - DateUtils.MILLIS_PER_DAY;
    }

    private static long zeroMilli() {
        return dateTime2milli(zeroDateTime());
    }

    private static long dateTime2milli(LocalDateTime dateTime) {
        return dateTime.toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
    }

    private static LocalDateTime zeroDateTime() {
        return LocalDateTime.now().with(LocalTime.MIN);
    }

    /**
     * 获取当天重置时间戳
     *
     * @return
     */
    public static long getCurrentDayResetTime() {
        if (getCurrentTime() >= tomorrowResetTime)
            resetTime();
        return dayResetTime;
    }

    /**
     * 获取明天重置时间戳
     *
     * @return
     */
    public static long getTomorrowResetTime() {
        if (getCurrentTime() >= tomorrowResetTime)
            resetTime();
        return tomorrowResetTime;
    }

    /**
     * 获取昨天重置时间戳
     *
     * @return
     */
    public static long getYesterdayResetTime() {
        if (getCurrentTime() >= tomorrowResetTime)
            resetTime();
        return yesterdayResetTime;
    }

    /**
     * 获取当前时间戳
     *
     * @return
     */
    public static long getCurrentTime() {
        return Instant.now().toEpochMilli();
        // return Clock.systemDefaultZone().millis();
    }

    /**
     * Timestamp转化为时间戳
     *
     * @param stamp
     * @return
     */
    public static long stamp2Millis(final Timestamp stamp) {
        return stamp.toInstant().toEpochMilli();
    }

    /**
     * 时间戳转化为Timestamp
     *
     * @param millis
     * @return
     */
    public static Timestamp millis2Stamp(final long millis) {
        return new Timestamp(millis);
    }

    /**
     * 获取当前年份
     *
     * @return
     */
    public static int getCurrentYear() {
        return LocalDate.now().getYear();
    }

    /**
     * 获取当前月份
     *
     * @return
     */
    public static int getCurrentMonth() {
        return LocalDate.now().getMonthValue();
    }

    /**
     * 获取当前星期数
     *
     * @return
     */
    public static int getCurrentWeek() {
        return LocalDate.now().getDayOfWeek().getValue();
    }

    /**
     * 指定格式的日期字符串转化为时间戳
     *
     * @param source
     * @return
     */
    public static long parse(final String source) {
        if (StringUtils.isBlank(source))
            return 0L;
        return parse("y-M-d H:m:s", source);
    }

    /**
     * 日期字符串转化为时间戳
     *
     * @param pattern
     * @param source
     * @return
     */
    public static long parse(final String pattern, final String source) {
        return dateTime2milli(LocalDateTime.parse(source, DateTimeFormatter.ofPattern(pattern)));
    }

    /**
     * 当前时间戳转化为指定格式的日期字符串
     *
     * @return
     */
    public static String format() {
        return format(getCurrentTime());
    }

    /**
     * 时间戳转化为指定格式的日期字符串
     *
     * @param millis
     * @return
     */
    public static String format(final long millis) {
        return format("y-M-d H:m:s", millis);
    }

    /**
     * 时间戳转化为日期字符串
     *
     * @param pattern
     * @param millis
     * @return
     */
    public static String format(final String pattern, final long millis) {
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), ZoneOffset.ofHours(8)).format(DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 获取下个整点时间戳
     *
     * @return
     */
    public static long getNextWholeHourTime() {
        return dateTime2milli(LocalDateTime.now().plusHours(1L).withMinute(0).withSecond(0).withNano(0));
    }

    /**
     * 获取下个每日重置时间戳
     *
     * @return
     */
    public static long getNextDayResetTime() {
        return dateTime2milli(zeroDateTime().plusDays(1L));
    }

    /**
     * 获取下个星期一重置时间戳
     *
     * @return
     */
    public static long getNextMondayResetTime() {
        return dateTime2milli(zeroDateTime().plusWeeks(1L).with(DayOfWeek.MONDAY));
    }

    /**
     * 获取下个每月一号重置时间戳
     *
     * @return
     */
    public static long getNextFirstDayOfMonthResetTime() {
        return dateTime2milli(zeroDateTime().plusMonths(1L).withDayOfMonth(1));
    }

    /**
     * 获取下个周末(星期六或星期日)重置时间戳
     *
     * @return
     */
    public static long getNextWeekendResetTime() {
        final LocalDateTime dateTime = zeroDateTime();
        final long sat = dateTime2milli(dateTime.with(DayOfWeek.SATURDAY));
        final long now = getCurrentTime();
        if (now < sat)
            return sat;
        final long sun = dateTime2milli(dateTime.with(DayOfWeek.SUNDAY));
        if (now >= sun)
            return dateTime2milli(dateTime.with(DayOfWeek.SUNDAY).plusDays(6));
        return sun;
    }

    /**
     * 获取间隔天数
     *
     * @param startTime
     * @param endTime
     * @return
     */
    public static int daysBetween(final long startTime, final long endTime) {
        return Period.between(LocalDate.ofInstant(Instant.ofEpochMilli(startTime), ZoneOffset.ofHours(8)), LocalDate.ofInstant(Instant.ofEpochMilli(endTime), ZoneOffset.ofHours(8))).getDays();
    }

    /**
     * 当前时间是否周末(星期六或星期日)
     *
     * @return
     */
    public static boolean isWeekend() {
        final LocalDateTime dateTime = zeroDateTime();
        return getCurrentDayResetTime() == dateTime2milli(dateTime.with(DayOfWeek.SATURDAY)) ||
                getCurrentDayResetTime() == dateTime2milli(dateTime.with(DayOfWeek.SUNDAY));
    }

    /**
     * 获取当前某一时间点的时间戳，如[10,30]即返回当前10:30的时间戳
     *
     * @param times
     * @return
     */
    public static long getTheTime(final List<Integer> times) {
        if (CollectionUtils.isEmpty(times) || times.size() < 2)
            return 0L;
        return getTheTime(times.get(0), times.get(1));
    }

    /**
     * 获取当前某一时间点的时间戳，如[10,30]即返回当前10:30的时间戳
     *
     * @param hour
     * @param min
     * @return
     */
    public static long getTheTime(final int hour, final int min) {
        return dateTime2milli(zeroDateTime().withHour(hour).withMinute(min).withSecond(0).withNano(0));
    }

    /**
     * 获取当天零点时间戳
     *
     * @return
     */
    public static long getCurrentDayZeroTime() {
        return zeroMilli();
    }

    /**
     * 获取当月第一天零点时间戳
     *
     * @return
     */
    public static long getCurrentFirstDayOfMonthZeroTime() {
        return dateTime2milli(zeroDateTime().withDayOfMonth(1));
    }

    /**
     * 获取当月最后一天零点时间戳
     *
     * @return
     */
    public static long getCurrentLastDayOfMonthZeroTime() {
        return dateTime2milli(zeroDateTime().withMonth(2).with(TemporalAdjusters.lastDayOfMonth()));
    }

    /**
     * 获取下月第一天零点时间戳
     *
     * @return
     */
    public static long getNextFirstDayOfMonthZeroTime() {
        return dateTime2milli(zeroDateTime().plusMonths(1L).withDayOfMonth(1));
    }

    /**
     * 获取下月最后一天零点时间戳
     *
     * @return
     */
    public static long getNextLastDayOfMonthZeroTime() {
        return dateTime2milli(zeroDateTime().plusMonths(1L).with(TemporalAdjusters.lastDayOfMonth()));
    }

    /**
     * 获取上月第一天零点时间戳
     *
     * @return
     */
    public static long getPreviousFirstDayOfMonthZeroTime() {
        return dateTime2milli(zeroDateTime().minusMonths(1L).withDayOfMonth(1));
    }

    /**
     * 获取上月最后一天零点时间戳
     *
     * @return
     */
    public static long getPreviousLastDayOfMonthZeroTime() {
        return dateTime2milli(zeroDateTime().minusMonths(1L).with(TemporalAdjusters.lastDayOfMonth()));
    }

    /**
     * 获取当前指定星期数的时间戳
     *
     * @param week 6.星期六
     * @param time 13:00
     * @return
     */
    public static long getWeekTime(final int week, final String time) {
        if (StringUtils.isBlank(time))
            return 0L;
        final String[] times = time.split(":");
        if (times.length < 2)
            return 0L;
        return dateTime2milli(zeroDateTime().with(DayOfWeek.of(week)).withHour(Integer.parseInt(times[0])).withMinute(Integer.parseInt(times[1])));
    }

    /**
     * 获取当前整分时间戳
     *
     * @return
     */
    public static long getCurrentMinuteTime() {
        return dateTime2milli(LocalDateTime.now().withSecond(0).withNano(0));
    }

    /**
     * 获取当前星期指定星期数的零点时间戳
     *
     * @param week 1-7
     * @return
     */
    public static long getCurrentWeekZeroTime(final int week) {
        return dateTime2milli(zeroDateTime().with(DayOfWeek.of(week)));
    }

    /**
     * 获取当前年份周数
     *
     * @return
     */
    public static int getWeekOfYear() {
        return LocalDate.now().get(ChronoField.ALIGNED_WEEK_OF_YEAR);
    }

    /**
     * 获取某个时间戳距离指定天数后的时间戳
     *
     * @param time
     * @param day
     * @return
     */
    public static long getApartDayTime(final long time, final int day) {
        return dateTime2milli(LocalDateTime.now().plusDays(day));
    }

    /**
     * 获取当天累计毫秒数的时间戳
     *
     * @param millis
     * @return
     */
    public static long getCurrentTimeBySeconds(final int millis) {
        return dateTime2milli(zeroDateTime().plusNanos(millis * 1000_000L));
    }
}
